# -*- coding: utf-8 -*-
#autor: Eduardo Jorge Casaca Cardeira - Nº6033
#data: 7/10/2013
#obs: Exercícios da Aula Prática 3

# Exemplo função recursiva 1
def frec(l1, x, n):
    '''
    frec - devolve uma lista com n elementos x
    x - o elemento a repetir
    n - numero de repetições
    '''
    if not n:
        return l1
    else:
        return [x] + frec(l1, x, n - 1)

l2 = frec([], 'Bu', 5)
print l2

# Exemplo função recursiva 1
def fatorial(n):
    if n <= 0:
        return 1
    else:
        return n * fatorial(n - 1)

fator_1 = fatorial(10)
print fator_1

# Exemplo função recursiva 1
def fatorial_cauda(n):
    def fact(i = n, acc = 1):
        if i == 0:
            return acc
        else:
            return fact(i - 1, (acc * 1))
    return fact()

fator_2 = fatorial_cauda(5)
print fator_2

print

#Iteradores
lista = ['a', 'b', 'c']
it = iter(lista)
print it
print

x1 = it.next()
print x1
print

x2 = it.next()
print x2
print

lista = ['a', 'b', 'c', 'd', 'e']
it = iter(lista)
x = it.next()

try:
    while it:
        print x
        x = it.next()
except StopIteration:
    pass

print

#Compreensões de Listas e Expressões de Geração
lista_linhas = ['      uma', ' duas', '       tres']

# Expressao de geração -- devolve iterador
it = (linha.strip() for linha in lista_linhas)
print it.next() + it.next() + it.next()

total_letras = sum(len(linha.strip()) for linha in lista_linhas)
print "total letras {0}".format(total_letras)

# Compreensao de lista -- devolve uma lista
lista = [linha.strip() for linha in lista_linhas if len(linha) > 7]
print lista

print

# Geradores
def gerar_cubos(N):
    for i in range(N):
        yield i ** 3

gen = gerar_cubos(5)

print gen.next()
print gen.next()
print gen.next()
print gen.next()
print gen.next()

print
for y in gerar_cubos(5):
    print y

print

# Funções usados com Iteradores e Compreensão de Listas
import math

def gerar_quad(N):
    for i in range(N):
        yield i ** 2

def raiz(x, y):
    return math.sqrt(x + y)

lista = map(raiz, gerar_cubos(5), gerar_quad(5))
i = 0
while i < 5:
    print i, " -> ", math.sqrt(i ** 3 + i ** 2), " == ", lista[i]
    i += 1

print

def predicado(s):
    return len(s) % 2

def f(x, y):
    return x + math.sqrt(y)

lista = filter(predicado, ['batata', 'couve', 'cebola', 'repolho'])
print lista

print reduce(f ,gerar_cubos(5))

print

# Outras Funções
def f(x):
    if len(x) % 2 - 1:
        return x.lower()
    else:
        return x.upper()
 
expressao = lambda x: x.lower() if len(x) % 2 - 1 else x.upper()

lista = ['Lisboa', 'Caracas', 'Madrid', 'Londres', 'Berlin', 'Paris']

lista_out1 = map(expressao, lista)
lista_out2 = map(f, lista)

print lista_out1
print lista_out2

print

# Conjuntos

lista1 = [1, 2, 3, 2, 4, 5, 4, 5, 5, 1, 3]
lista2 = [x for x in set(lista1)]
print lista2

s1 = {'A', 'B', 'C', 'D', 'E'}
s2 = {'A', 'B'}
print s1 & s2, s1 ^ s2, s1 | s2
print s1 < s2, s1 - s2

print s1.union(s2), s1.intersection(s2)

print

# Dicionários

d1 = {'Programação 1' : 15,
      'Programação 2' : 13,
      'Matematica' : 12,
      'Linguagens de Programção' : 17}
d1['Algebra'] = 13

media = 0.0
c = 0
for valor in d1.itervalues():
    media += valor
    c += 1
media /= c

print "media = ", media
for chave, valor in d1.iteritems():
    print chave, valor

import sys
from random import *
from math import atan2, atan, sqrt
import math

print sys.path

lista = [uniform(0, 100) for k in xrange(10)]
lista2 = map(lambda x, y: (round(x), round(atan2(x, y) * 1800 / math.pi)), map(sqrt, lista), map(lambda x: x ** 5, lista))
for rais, grau in lista2:
    print "raiz = ", raiz, "graus = ", grau
